﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Text;

namespace EBA.Dynamic
{
    /// <summary>
    /// 动态类型转换工厂
    /// </summary>
    public static class DynamicFactory
    {
        static Dictionary<Type, Type> DYNAMIC_TYPES = new Dictionary<Type, Type>();

        /// <summary>
        /// 将<paramref name="contextObject"/>动态转为<typeparamref name="TConversion"/>的对象。
        /// </summary>
        /// <typeparam name="TConversion">目标转换类型</typeparam>
        /// <param name="contextObject">待转换对象</param>
        /// <returns></returns>
        public static TConversion DynamicCastTo<TConversion>(this object contextObject)
        {
            return DynamicCastTo<TConversion, DynamicContext>(contextObject);
        }

        /// <summary>
        /// 将<paramref name="contextObject"/>动态转为<typeparamref name="TConversion"/>的对象。
        /// </summary>
        /// <typeparam name="TConversion">目标转换类型</typeparam>
        /// <typeparam name="TDynamicContext">动态上下文类型</typeparam>
        /// <param name="contextObject">待转换对象</param>
        /// <returns></returns>
        public static TConversion DynamicCastTo<TConversion, TDynamicContext>(this object contextObject) where TDynamicContext : IDynamicContext
        {
            var dynamicObject = DynamicCastTo(contextObject, typeof(TConversion), typeof(TDynamicContext));

            return (TConversion)dynamicObject;
        }

        /// <summary>
        /// 将<paramref name="contextObject"/>动态转换为<paramref name="conversionType"/>的对象。
        /// </summary>
        /// <param name="contextObject">待转换对象</param>
        /// <param name="conversionType">目标转换类型</param>
        /// <param name="dynamicContextType">动态上下文类型</param>
        /// <returns></returns>
        public static object DynamicCastTo(this object contextObject, Type conversionType, Type dynamicContextType)
        {
            //if (contextObject == null)
            //{
            //    throw new NotSupportedException(string.Format("A null object can NOT be castted to {0}.", conversionType));
            //}
       
            Type dynamicType;

            if (DYNAMIC_TYPES.ContainsKey(conversionType))
            {
                dynamicType = DYNAMIC_TYPES[conversionType];
            }
            else
            {
                lock (DYNAMIC_TYPES)
                {
                    if (DYNAMIC_TYPES.ContainsKey(conversionType))
                    {
                        dynamicType = DYNAMIC_TYPES[conversionType];
                    }
                    else
                    {
                        dynamicType = DynamicTypeBuilder.BuildType(conversionType, dynamicContextType);
                        DYNAMIC_TYPES.Add(conversionType, dynamicType);
                    }
                }
            }

            var dynamicObject = Activator.CreateInstance(dynamicType) as IDynamicContext;
            dynamicObject.Initialize(contextObject);

            return dynamicObject;

        }
    }
}
